package com.expires.desigin.singleton;

/**
 * @Author：Administrator
 * @Date：2022/6/20/0020 21:50
 * @Versiion：1.0
 *
 *
 *  23种设计模式之 单例模式
 *
 *  确保只有一个对象被创建，不需要实例化该类对象
 */

public class Singleton {

    private static Singleton singleton = null;

    /**
     * 单例模式的标志 私有化构造 不能被new
     * */
    private Singleton(){}

    /**
    *   线程不安全   懒汉式单例（在第一次调用的时候实例化自己）
    *   不支持多线程：  当一个线程调用时 此时还没有创建这个对象 就会去创建对象  此时如果还有一个线程进来发现 还没有创建完这个对象 于是也去创建对象
    *   此时就会有多个对象 导致线程不安全
    **/
    /*
    public static Singleton GetInstance(){
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }
    */

    /***
     * 懒汉式单例  线程安全的   使用了synchronized 加锁修饰
     * @return
     */
    /*public static synchronized Singleton GetInstance(){
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }*/


    /**
     * 饿汉式单例  在初始化的时候就去创建对象 【类加载的时候就去创建】
     *
     * 不管用不用 都会创建出来 有点浪费内存
     *
     */
    /*private static Singleton singleton1 = new Singleton();
    public static Singleton GetInstance(){
        return singleton1;
    }*/


    /****
     * 双重检查锁 单例  安全且能在多线程下保持高效 dcl
     *
     * 双检锁存在的问题： 对象需要用volatile修饰，
     *
     * singleton = new Singleton();
     *    1、给singleton分配内存
     *    2、调用new Singleton() 创建对象  存放于堆内存中
     *    3、将singleton 指向分配的内存空间(执行完这步骤singleton 才是非null)
     *
     *  但上述步骤并非是原子操作，JVM即时编译时存在指令重排序的优化
     *  2、3的顺序是不能保证的
     *
     *  因此使用volatile 关键字  防止指令重排  内部使用了内存屏障保证 lock前都会被执行成功
     *  volatile 有两个关键点：1、线程可见性  2、防止指令重排序（lock原语）
     * @return
     */
    public static Singleton GetInstance(){
        if(singleton == null){
            synchronized (Singleton.class){
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }


    /**
     * 静态内部类形式实现单例模式
     * 这种方式能达到双检锁方式一样的功效，但实现更简单。
     * 对静态域使用延迟初始化，应使用这种方式而不是双检锁方式。
     * 这种方式只适用于静态域的情况，双检锁方式可在实例域需要延迟初始化时使用。
     * */
    /*private static class SingleHolder{
        //静态内部类
        private static Singleton singleton = new Singleton();
    }
    public static Singleton getSingle(){
        return SingleHolder.singleton;
    }*/


    public static void main(String[] args) {
        /*Singleton singleton1 = Singleton.GetInstance();
        Singleton singleton2 = Singleton.GetInstance();*/

        EnumSingleton singleton1 = EnumSingleton.SINGLETON;
        EnumSingleton singleton2 = EnumSingleton.SINGLETON;

        //相同的引用地址
        System.out.println(singleton1 == singleton2);
        singleton1.say("张三");
        singleton2.say("李四");

        System.out.println(singleton1.add(5));
        System.out.println(singleton2.add(6));
    }
}
